#include "TcpServer.hpp"
#include "Protocol.hpp"
#include <memory>

Response Calculator(const Request &req)
{
    // 根据op选项进行计算
    Response resp(0, 0);
    switch (req.op_)
    {
    case '+':
        resp.result_ = req.x_ + req.y_;
        break;
    case '-':
        resp.result_ = req.x_ - req.y_;
        break;
    case '*':
        resp.result_ = req.x_ * req.y_;
        break;
    case '/':
        if (req.y_ == 0) // 除零错误，需要设置状态码
            resp.code_ = 1;
        else
            resp.result_ = req.x_ / req.y_;
        break;
    case '%':
        if (req.y_ == 0) // 模零错误，需要设置状态码
            resp.code_ = 2;
        else
            resp.result_ = req.x_ % req.y_;
        break;
    default: // 输入错误，需要设置状态码
        resp.code_ = -1;
        break;
    }
    return resp; // 返回结果（响应：结构体对象）
}

void Call(Connection *conet, std::string &str)
{
    logMessage(DEBUG, "call service, sock is %d, str is# %s", conet->_sock, str.c_str());

    // 1、反序列化
    Request reque;
    reque.Deserialized(str);

    // 2、业务处理获得结果
    Response respon = Calculator(reque);

    // 3、将结果序列化，编码构建应答
    std::string result_str = respon.Serialize();
    result_str = Encode(result_str);

    // 4、将结果返回给客服端：这不是我上层需要关系的事，交给Tcp服务器处理
    // a、将待发送数据交给当前sock的输出缓冲区
    conet->_outbuffer += result_str;
    // b、服务器中，写入事件默认关闭，按需打开。这里，要发送数据，就需要想办法，让底层的写事件就绪。
    // c、这就是使能读写函数EnableReadWirte的诞生与connection中Tcp服务器的回值指针的用处：用于触发发送的动作
    conet->_ptsv->EnableReadWirte(conet, true, true); 
    // d、需要注意，一旦我们开启EPOLLOUT，epoll会自动立马触发一次发送事件就绪。
    // e、由于我们写的Sender的逻辑，只要触发了这里的首次调用，后续如果需要保持服务端数据发送，epoll自动监测。
}



void Usage(std::string proc)
{
    std::cout << "\n Usage: " << proc << " port\n"
              << std::endl;
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        exit(1);
    }

    uint16_t port = atoi(argv[1]);
    std::unique_ptr<TcpServer> server(new TcpServer(port)); // 构造服务器

    server->Dispather(Call); // 进行任务派发

    return 0;
}